package transport

import (
	"fmt"
	"gitee.com/slh1992/plugin-sip/sip"
	"net"
	"strings"
)

type UDPServer struct {
	Statistic
	addr      string
	conn      *Connection
	readChan  chan *Packet
	writeChan chan *Packet
	done      chan struct{}
	Keepalive bool
	//Sessions  sync.Map // key is remote-addr的string , value:*Connection。UDP不需要
}

func NewUDPServer(port uint16) IServer {
	addrStr := fmt.Sprintf(":%d", port)

	return &UDPServer{
		addr:      addrStr,
		readChan:  make(chan *Packet, 2048),
		writeChan: make(chan *Packet, 2048),
		done:      make(chan struct{}),
	}
}

func (s *UDPServer) IsReliable() bool {
	return false
}

func (s *UDPServer) Name() string {
	return fmt.Sprintf("udp client to:%s", s.addr)
}

func (s *UDPServer) IsKeepalive() bool {
	return s.Keepalive
}

func (s *UDPServer) StartAndWait() error {
	addr, err := net.ResolveUDPAddr("udp", s.addr)
	if err != nil {
		fmt.Println("Can't resolve address: ", err)
		return err
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Println("Error listenUDP :", err)
		return err
	}

	udpConnection := newUDPConnection(conn)
	s.conn = &udpConnection
	fmt.Println("start udp server at: ", s.addr)

	//心跳线程
	if s.Keepalive {
		//TODO:start heartbeat thread
	}
	go func() {
		defer func() {
			_ = conn.Close()
		}()
		//读线程
		for {
			select {
			case <-s.done:
				return
			default:
				data := make([]byte, 2048)
				n, remoteAddr, err := conn.ReadFromUDP(data)
				if err != nil {
					fmt.Println("failed to read UDP msg because of ", err.Error())
					continue
				}
				s.readChan <- &Packet{
					Addr: remoteAddr,
					Data: data[:n],
				}
			}
		}
	}()
	return nil
}
func (s *UDPServer) ReadPacketChan() <-chan *Packet {
	return s.readChan
}
func (s *UDPServer) WritePacket(packet *Packet) {
	s.writeChan <- packet
}

func (s *UDPServer) Close() error {
	//所有session离线和关闭处理
	close(s.done)
	return (*s.conn).Close()
}
func (s *UDPServer) CloseOne(addr string) {
	//处理某设备离线
}

func (s *UDPServer) Conn(addr string) *Connection {
	return s.conn
}

func (s *UDPServer) SendRespond(m *sip.Message) {
	str, _ := sip.Encode(m)
	if m.DestAdd == nil {
		host := m.Via.Host
		if m.Via.Params["rport"] != "" && strings.IndexByte(host, ':') != -1 {
			host += ":" + m.Via.Port
		}
		network, err := net.ResolveUDPAddr(strings.ToLower(m.Via.Transport), host)
		if err != nil {
			fmt.Println("网络地址解析错误：", err.Error())
		}
		m.DestAdd = network
	}
	(*s.conn).WriteTo(str, m.DestAdd)
}
